#ifndef INC_RAY_TRACER_H_
#define INC_RAY_TRACER_H_
#include "Cubemap.h"
#include <iostream>
#include "geometry.h"
#include "material.h"
#include "rtobject.h"
#include "camera.h"
#include "light.h"
#include <vector>
#include "image.h"
#include "Cubemap.h"
#include <limits>
#include <cassert>
#include <sstream>

#define SMALL_AMOUNT      1e-4

// Una estructura para guardar cada sample con su peso
struct TSample {
	float w;
	COLOR color;
	TSample( float aw, const COLOR &c ) : w(aw), color(c) { }
};

enum TSamplingMode {
	POINT_SAMPLING
	,   UNIFORM_SAMPLING
	,   JITTERED_SAMPLING
	,	ADAPTATIVE_SAMPLING
};

typedef std::vector<TSample > VSamples;

/*-<==>-----------------------------------------------------------------
/ Raytracer
/---------------------------------------------------------------------*/
class CRayTracer {
	// Maximum recursion level allowed while computing 
	// lines 
	int         max_recursion_level;


	LRTObjects  objects; 			// List of objects defined in the scene
	MMaterials  materials; 		// Map of materials defined in the scene
	LLights     lights; 			// List of lights defined in the world


	Cubemap cubemap;

	COLOR trace (CLine &line, int profundityLevel);
	bool intersects (CLine &line);
	bool instersectsShade(CLine &line);
	void background (CLine &line);
	COLOR computeObjectHitColorAmount(CLine &line, int profundityLevel);
	COLOR computeColorForPixel( float x, float y, TSamplingMode sampling_mode, int nsamples );
	void generateAdaptativeSamplingImage(CBitmap& image);
	bool pixelNeighborsChanged(int x, int y,CBitmap& image);
	SCALAR ambientOcclusionEffect(VECTOR& position, VECTOR& normal);
	VECTOR randomNormal(VECTOR & normal);
	VECTOR hemisphereVector(VECTOR & normal, int numSample);
public:
	CCamera     camera; 			// The camera to render the scene from
	CRayTracer();
	void render(const char * filename, int it,TSamplingMode smode);
	void load();              // defined in main.cpp
	bool loadSnowflake (const char *filename); // defined in main.cpp
	void renderAnimation (int num_frames);
	void showStats(const char *filename);
	COLOR background_color;
	bool ambientOcclusion;
	int numOcclusionSamples;
	float maxOcclusionDistance;
	SCALAR occlusionAmount;


	//Statistics:
	unsigned long numCameraLines;
	unsigned long numLinesTraced;
	unsigned long numLinesReflex;
	unsigned long numLinesRefrac;
	unsigned long numLinesShade;
	unsigned long numIntersections;
	unsigned long numHitIntersections;
	unsigned long numSuperSampledPixels;


};

// Send a vector to a output stream
std::ostream &operator << (std::ostream &os, const VECTOR &v);

#endif
